package com.example.demogateway.filters;

import com.example.demogateway.cache.CacheUtils;
import com.example.demogateway.utils.TraceIdUtils;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;



@Component
public class AccessLogGlobalFilter implements GlobalFilter, Ordered  {
    private static final Logger log = LoggerFactory.getLogger(AccessLogGlobalFilter.class);
    public static final String traceId = "traceId";
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        //这个地方一定要保留MDC.remove,否则会重复上次traceId
        MDC.remove("traceId");
        String path = request.getPath().pathWithinApplication().value();
        String   traceId = TraceIdUtils.generateTraceId();
        log.info("traceId={}",traceId);
        MDC.put("traceId",traceId);

        log.info("请求路径:{}", path);
        long start = System.currentTimeMillis();

        Mono<Void> rep = null;
        String token = null;
        String currentUser = null;
        try{
             token = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
             currentUser = CacheUtils.getString(token);
//             将登陆用户信息放到MDC里
            MDC.put("token",token);
            MDC.put("currentUser",currentUser);
            if(StringUtils.isEmpty(currentUser)){
                log.info("请求路径:{}，token为："+token+"，用户身份为nulll", path);
            }

            rep =  chain.filter(  exchange.mutate().request(request).build()).then(
                    Mono.fromRunnable(() -> {

            ServerHttpResponse response = exchange.getResponse();
            HttpStatus statusCode = response.getStatusCode();
            long end = System.currentTimeMillis();
//由于MDC里traceId丢失，所以在这里重复写一遍
            MDC.put("traceId",traceId);
            log.info("请求路径:{},响应码:{},耗时：{},traceId="+traceId, path, statusCode,(end-start));
        }));
        }catch (Exception e){
            log.error("全局异常，e=",e);
            throw e;
        }

        return rep;
    }

    /**
     * 数字越大优先级越低
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}


